package com.bestcem.xm.user.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.constant.AppRequestErrorCode;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.IpUtil;
import com.bestcem.xm.component.security.annotation.AuthIgnore;
import com.bestcem.xm.component.security.annotation.XmAuth;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.user.constant.CookieConstant;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.controller.vo.auth.request.FastLoginVO;
import com.bestcem.xm.user.controller.vo.auth.request.OrgFastLoginVO;
import com.bestcem.xm.user.controller.vo.auth.request.PhoneOrEmailFastLoginVO;
import com.bestcem.xm.user.controller.vo.user.*;
import com.bestcem.xm.user.controller.vo.user.request.*;
import com.bestcem.xm.user.enums.MfaSettingAuthMethodEnum;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.third.LuosimaoService;
import com.bestcem.xm.user.util.business.CustomSettingThreadLocalUtil;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import com.bestcem.xm.user.util.business.UserUtil;
import com.bestcem.xm.user.util.business.captcha.CaptchaUtil;
import com.bestcem.xm.user.util.convert.UserConvert;
import com.bestcem.xm.user.util.convert.UserLoginConvert;
import com.bestcem.xm.user.util.converter.AuthorizationConverter;
import com.bestcem.xm.user.util.converter.OrganizationConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

/**
 * 登录注册controller
 *
 * @author wangyunyun <yunyun.wang@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/29 10:30
 */
@Slf4j
@RestController
@RequestMapping(value = "/authorize")
public class AuthorizationController {

    @Resource
    private UserLoginConvert userLoginConvert;

    @Resource
    private UserUtil userUtil;

    @Autowired
    private SsoService ssoService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserAuthService userAuthService;

    @Resource
    private UserWxService userWxService;

    @Resource
    private UserConvert userConvert;

    @Resource
    private OrganizationService organizationService;

    @Resource
    private UserService userService;

    @Resource
    private UserMfaSettingService userMfaSettingService;

    @Resource
    private CaptchaUtil captchaUtil;

    @Resource
    private DingTalkService dingTalkService;

    @Autowired
    private LuosimaoService luosimaoService;

    @Autowired
    private UserCacheUtil userCacheUtil;


    /**
     * 静默登陆
     *
     * @param orgCode   租户code
     * @param encrypt   加密请求参数
     * @param signature 签名
     * @return XmResultJson<UserLoginVO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/29 11:30
     */
    @AuthIgnore
    @PostMapping("/silent/token/")
    public XmResultJson<UserLoginVO> silentLogin(HttpServletRequest request, HttpServletResponse response,
                                                 @RequestParam(name = "t_org_code", required = false) String orgCode,
                                                 @RequestParam(name = "t_encrypt", required = false) String encrypt,
                                                 @RequestParam(name = "t_signature", required = false) String signature) {
        // 静默登陆
        String ipAddress = IpUtil.getIpAddress(request);
        ServiceResult<UserLoginDTO> result = ssoService.silentLogin(orgCode, encrypt, signature, ipAddress);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        captchaUtil.clearLoginCaptcha(response, result.getData().getUserName(), ipAddress);
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 根据凭证获取登录token(CAS)
     *
     * @param request
     * @param orgCode
     * @param ticket
     * @param service
     * @return XmResultJson<UserLoginVO>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @version v1.0
     * @date 2022/3/29 16:47
     * @deprecated 弃用
     */
    @AuthIgnore
    @PostMapping("/sso/token/")
    @Deprecated
    public XmResultJson<UserLoginVO> casLogin(HttpServletRequest request,
                                              @RequestParam(name = "org_code", required = false) String orgCode,
                                              String ticket, String service) {
        // 根据凭证获取登录token(CAS)
        ServiceResult<String> corpCode = userUtil.getCorpCode(orgCode, request.getServerName());
        if (!corpCode.isSuccess()) {
            return XmResultJson.fail(corpCode.getErrorData(), corpCode.getMsg());
        }
        orgCode = corpCode.getData();
        ServiceResult<UserLoginDTO> result = ssoService.casLogin(orgCode, ticket, service, IpUtil.getIpAddress(request));
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * MFA登录
     *
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/6/9 16:55
     */
    @AuthIgnore
    @PostMapping("/mfa/token/")
    public XmResultJson<Object> mfaLogin(@Valid @RequestBody MfaLoginRequestVO vo) {
        ServiceResult<UserDTO> userDTOServiceResult = userService.selectById(vo.getUserId());
        if (!userDTOServiceResult.isSuccess() || Objects.isNull(userDTOServiceResult.getData())) {
            XmResultJson.fail(AppResourceErrorCode.NOT_FOUND, "user[id=" + vo.getUserId() + "] not found");
        }

        String key;
        if (MfaSettingAuthMethodEnum.MFASETTING_AUTH_METHOD_SMS.getType().equals(vo.getAuthMethod())) {
            key = userCacheUtil.buildKey(UserCacheKeyConstant.USER_MFA_SMS_PREFIX, userDTOServiceResult.getData().getPhone());
        } else if (MfaSettingAuthMethodEnum.MFASETTING_AUTH_METHOD_EMAIL.getType().equals(vo.getAuthMethod())) {
            key = userCacheUtil.buildKey(UserCacheKeyConstant.USER_MFA_EMAIL_PREFIX, userDTOServiceResult.getData().getEmail());
        } else {
            return XmResultJson.fail(AppRequestErrorCode.PARAM_RANGE, "auth_method out of range");
        }
        String cacheCode = userCacheUtil.get(key);
        if (StringUtils.isBlank(cacheCode) || !cacheCode.equalsIgnoreCase(vo.getVcode())) {
            return XmResultJson.fail(ValidationErrorCodeEnum.VCODE_ERROR, "验证码错误");
        }

        if (Boolean.TRUE.equals(vo.getSkip())) {
            userMfaSettingService.userSetSkipMfa(userDTOServiceResult.getData().getUserId());
        }
        ServiceResult<UserGetTokenResultDTO> result = dingTalkService.getTokenByUser(userDTOServiceResult.getData());
        if (!result.isSuccess()) {
            return XmResultJson.fail(result.getErrorData().getCode(), result.getErrorData().getMsg());
        }
        UserGetTokenResultDTO dto = result.getData();
        return XmResultJson.success(AuthorizationConverter.tokenDtoToVO(dto));
    }

    /**
     * 判断是否是sso登录【拿配置】
     *
     * @param request
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/30 21:49
     */
    @AuthIgnore
    @GetMapping("/sso/")
    public XmResultJson<HashMap<String, Object>> checkSso(@RequestParam(name = "org_code", required = false) String orgCode,
                                                          HttpServletRequest request) {
        String code = "";
        if (StringUtils.isNotBlank(orgCode)) {
            code = orgCode;
        } else {
            ServiceResult<String> corpCode = userUtil.getCorpCode(request.getServerName());
            if (!corpCode.isSuccess()) {
                return XmResultJson.fail(corpCode.getErrorData(), corpCode.getMsg());
            }
            code = corpCode.getData();
        }

        ServiceResult<HashMap<String, Object>> serviceResult = ssoService.checkSso(code);
        if (serviceResult.isSuccess()) {
            return XmResultJson.success(serviceResult.getData());
        }
        return XmResultJson.fail(serviceResult.getErrorData(), serviceResult.getMsg());
    }

    /**
     * 根据xm_ticket,sso登录【从redis中拿UserInfo，生成token】
     *
     * @param request
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/30 21:50
     */
    @PostMapping("/sso/openplatform/token/")
    @AuthIgnore
    public XmResultJson<Object> getToken(@RequestBody SsoGetTokenVO vo,
                                         HttpServletRequest request) {
        ServiceResult<String> corpCode = userUtil.getCorpCode(request.getServerName());
        if (!corpCode.isSuccess()) {
            return XmResultJson.fail(corpCode.getErrorData(), corpCode.getMsg());
        }
        String orgCode = corpCode.getData();

        log.info("sso登录xm_ticket_id:{}", vo.getXmTicketId());
        String infoName = String.format(UserCacheKeyConstant.USER_INFO, orgCode, vo.getXmTicketId());
        Object userInfo = redisService.get(infoName);
        if (Objects.isNull(userInfo)) {
            return XmResultJson.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "无法通过xmTicketId查询userInfo");
        }
        JSONObject jsonObject = JSON.parseObject(userInfo.toString());
        String userName = jsonObject.get("userName").toString();
        String name = jsonObject.get("name").toString();
        ServiceResult<Object> serviceResult = ssoService.getToken(orgCode, userName, name);
        if (serviceResult.isSuccess()) {
            return XmResultJson.success(serviceResult.getData());
        }
        return XmResultJson.fail(serviceResult.getErrorData(), serviceResult.getMsg());
    }


    /**
     * 微信公众号获取token ok
     * apps_mysql/auth/handlers.py:985
     *
     * @param loginVO
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.controller.vo.user.UserWxLoginVO>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/04/19 18:36
     */
    @AuthIgnore
    @PostMapping("/wxoffiaccount/token/")
    public XmResultJson<UserWxLoginVO> wxOffiLogin(@RequestBody @Validated WxLoginVO loginVO) {
        ServiceResult<WxLoginDTO> wxLoginResult = userWxService.wxLogin(loginVO.getSessionId());
        if (!wxLoginResult.isSuccess()) {
            // mfa 失败返回
            return XmResultJson.fail(userConvert.wxLoginDTO2VO(wxLoginResult.getData()), Integer.valueOf(wxLoginResult.getErrorCode()), wxLoginResult.getMsg());
        }
        UserWxLoginVO wxLoginVO = userConvert.wxLoginDTO2VO(wxLoginResult.getData());
        return XmResultJson.success(wxLoginVO);
    }

    /**
     * 微信小程序用户登录查询 ok
     *
     * @param requestVO
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.controller.vo.user.WxAuthViewVO>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/10 21:03
     */
    @AuthIgnore
    @PostMapping("/wxminiprogram/users/")
    public XmResultJson<WxAuthViewVO> wxAuthView(@RequestBody WxAuthViewRequestVO requestVO) {
        if (StringUtils.isBlank(requestVO.getCode()) || StringUtils.isBlank(requestVO.getIv()) || StringUtils.isBlank(requestVO.getEncryptedData())) {
            return XmResultJson.fail(AppRequestErrorCode.PARAM_LOST, "code or encryptedData or iv is empty");
        }
        WxAuthViewRequestDTO requestDTO = userConvert.wxAuthViewVO2DTO(requestVO);
        ServiceResult<WxAuthViewDTO> wxAuthViewResult = userWxService.wxAuthView(requestDTO);
        if (!wxAuthViewResult.isSuccess()) {
            return XmResultJson.fail(wxAuthViewResult.getErrorData(), wxAuthViewResult.getMsg());
        }
        WxAuthViewVO wxAuthViewVO = userConvert.wxAuthViewDTO2VO(wxAuthViewResult.getData());
        return XmResultJson.success(wxAuthViewVO);
    }


    /**
     * 微信用户关联User,签发token ok
     * 废弃 V2替代
     *
     * @param requestVO
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.controller.vo.user.WxTokenViewVO>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/05/10 21:05
     */
    @AuthIgnore
    @PostMapping("/wxminiprogram/token/")
    public XmResultJson<WxTokenViewVO> wxTokenView(@RequestBody @Validated WxTokenViewRequestVO requestVO) {
        WxTokenViewRequestDTO requestDTO = userConvert.wxTokenViewVO2DTO(requestVO);
        ServiceResult<WxTokenViewDTO> wxTokenViewServiceResult = userWxService.wxTokenView(requestDTO);
        if (!wxTokenViewServiceResult.isSuccess()) {
            return XmResultJson.fail(wxTokenViewServiceResult.getErrorData(), wxTokenViewServiceResult.getMsg());
        }
        WxTokenViewVO wxTokenViewVO = userConvert.wxTokenViewDTO2VO(wxTokenViewServiceResult.getData());
        return XmResultJson.success(wxTokenViewVO);
    }


    /**
     * 小程序内切换账号接口 ok
     * apps_mysql/auth/handlers.py:1345
     *
     * @param
     * @return WxSwitchVO 登录公司展示信息
     * @author jishuo.yan <jishuo.yan@idiaoyan.com>
     * @date 2022/03/02 16:30
     */
    @XmAuth
    @PostMapping("/wxminiprogram/switch/")
    public XmResultJson<WxMiniSwitchVO> wxSwitchView() {
        WxMiniSwitchVO wxMiniSwitchVO = new WxMiniSwitchVO();
        String userId = SecurityContextHolder.getToken().getUserId();
        ServiceResult<List<WxSwitchDTO>> result = userWxService.wxAccountSwitch(userId);
        if (result.isSuccess()) {
            wxMiniSwitchVO.setMultiOrg(Boolean.TRUE);
            wxMiniSwitchVO.setWxSwitchVOList(userConvert.wxSwitchDTOList2VO(result.getData()));
            return XmResultJson.success(wxMiniSwitchVO);
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 微信小程序 通过unionID无感登陆 ok
     * apps_mysql/auth/handlers.py:848
     *
     * @param
     * @return UserLoginVO
     * @author jishuo.yan <jishuo.yan@idiaoyan.com>
     * @date 2022/03/30 13:53
     */
    @AuthIgnore
    @PostMapping("/wxminiprogram/v2/token/")
    public XmResultJson<UserWxLoginVO> wxTokenV2View(@RequestBody @Validated WxTokenV2ViewVO wxTokenV2ViewVO) {
        ServiceResult<WxLoginDTO> result = userWxService.loginBySessionId(wxTokenV2ViewVO.getSessionId());
        if (result.isSuccess()) {
            return XmResultJson.success(userConvert.wxLoginDTO2VO(result.getData()));
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 微信小程序用户登录V2 ok
     * apps_mysql/auth/handlers.py:930
     *
     * @param requestVO
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @params code: 用户登录凭证（有效期五分钟）。开发者需要在开发者服务器后台调用 auth.code2Session，使用 code 换取 openid 和 session_key 等信息。https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
     * @params encryptedData: 包括敏感数据在内的完整用户信息的加密数据 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
     * @params iv: 加密算法的初始向量
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/02 16:40
     */
    @AuthIgnore
    @PostMapping("/wxminiprogram/v2/users/")
    public XmResultJson<Object> wxAuthViewV2(@RequestBody WxAuthViewV2RequestVO requestVO) {
        if (StringUtils.isBlank(requestVO.getEncryptedData()) && StringUtils.isBlank(requestVO.getIv())) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, "code or encryptedData or iv is empty");
        }
        ServiceResult<Object> result = userWxService.wxAuthViewV2(userConvert.wxAuthViewV2RequestVO2DTO(requestVO));
        if (result.isSuccess()) {
            return XmResultJson.success(result.getData());
        }
        // mfa 失败返回
        return XmResultJson.fail(result.getData(), Integer.valueOf(result.getErrorCode()), result.getMsg());
    }

    /**
     * 企业微信中打开微信小程序 login 后获取并存储用户凭证 ok
     * SaaS前端未使用
     *
     * @param codeVO
     * @return com.bestcem.xm.util.XmResultJson<java.lang.String>
     * @author Linzhijian <zhijian.lin@idiaoyan.com>
     * @date 2022/06/02 16:54
     */
    @AuthIgnore
    @PostMapping("/wxworkminiprogram/code/")
    public XmResultJson<String> wxWorkCode(@RequestBody @Validated WxWorkCodeVO codeVO) {
        ServiceResult<String> result = userWxService.wxWorkCode(codeVO.getCode());
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 获取company信息
     * <p>
     * python引用：apps_mysql.auth.handlers.AuthCompanyHandler
     * * - “@decorators.render_json”
     *
     * @param orgCode 组织代码
     * @param request 请求信息
     * @return companyVO 公司信息
     * @author jishuo.yan <jishuo.yan@idiaoyan.com>
     * @date 2022/03/01 15:30
     */
    @GetMapping("/company/")
    @AuthIgnore
    public XmResultJson<CompanyVO> getCompanyInfo(@RequestParam(value = "org_code", required = false) String orgCode,
                                                  HttpServletRequest request) {
        // 获取corpCode
        ServiceResult<String> corpCode = userUtil.getCorpCode(orgCode, request.getServerName());
        if (!corpCode.isSuccess()) {
            return XmResultJson.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, "organization code not exist.");
        }

        orgCode = corpCode.getData();
        // 获取ip地址
        String ipAddress = IpUtil.getIpAddress(request);
        ServiceResult<CompanyDTO> result = organizationService.getCompanyInfo(ipAddress, orgCode);
        // 从ThreadLocal删除租户自定义配置信息
        CustomSettingThreadLocalUtil.removeCustomSetting();
        if (result.isSuccess()) {
            return XmResultJson.success(OrganizationConverter.companyDTOtoVO(result.getData()));
        }
        return XmResultJson.fail(result.getErrorData(), result.getMsg());
    }

    /**
     * 手机号码快速登录
     *
     * @param fastLoginVO 登录参数
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/4 14:30
     */
    @AuthIgnore
    @PostMapping("/fast/token/")
    public XmResultJson<UserLoginVO> fastLogin(HttpServletRequest request, @RequestBody FastLoginVO fastLoginVO) {
        String mobile = fastLoginVO.getPhone();
        String vcode = fastLoginVO.getVcode();
        // 手机号+验证码快速登录
        ServiceResult<UserLoginDTO> result = userAuthService.fastLogin(mobile, vcode, IpUtil.getIpAddress(request));
        // 处理失败
        if (!result.isSuccess() || Objects.isNull(result.getData())) {
            return XmResultJson.fail(userLoginConvert.userLoginDto2Vo(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 一个手机号码对应多个用户时快速登录 选择企业快速登录
     *
     * @param request        http请求对象
     * @param orgFastLoginVO 登录参数
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/6 11:30
     */
    @AuthIgnore
    @PostMapping("/fast/org/token/")
    public XmResultJson<UserLoginVO> fastLoginByOrg(HttpServletRequest request, @RequestBody OrgFastLoginVO orgFastLoginVO) {
        // 手机号+验证码 选择企业快速登录
        ServiceResult<UserLoginDTO> result = userAuthService
                .fastLoginByOrg(orgFastLoginVO.getOrgCode(), orgFastLoginVO.getSessionId(), IpUtil.getIpAddress(request));
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(userLoginConvert.userLoginDto2Vo(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 手机号码和邮箱登录
     *
     * @param request     http请求对象
     * @param fastLoginVO 登录参数
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/6 14:30
     */
    @AuthIgnore
    @PostMapping("/v3/token/")
    public XmResultJson<UserLoginVO> phoneOrEmailFastLogin(HttpServletRequest request, HttpServletResponse response,
                                                           @RequestBody PhoneOrEmailFastLoginVO fastLoginVO) {
        // 手机号/邮箱+密码登录
        String ipAddress = IpUtil.getIpAddress(request);
        ServiceResult<UserLoginDTO> result = userAuthService
                .phoneOrEmailFastLogin(response, fastLoginVO.getUsername(), fastLoginVO.getPassword(), fastLoginVO.getSessionId(), ipAddress);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(userLoginConvert.userLoginDto2Vo(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 公司代号登录
     *
     * @param request    http请求对象
     * @param response   http响应对象
     * @param orgLoginVO 用户登陆vo
     * @param captchaKey 图形验证码缓存key
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/6 14:30
     */
    @AuthIgnore
    @PostMapping("/v2/token/")
    public XmResultJson<UserLoginVO> orgAndUsernameLogin(HttpServletRequest request, HttpServletResponse response, @RequestBody OrgLoginVO orgLoginVO,
                                                         @CookieValue(value = CookieConstant.CAPTCHA_KEY, required = false) String captchaKey,
                                                         @CookieValue(value = CookieConstant.LOGIN_CAPTCHA_COUNT, required = false) Long loginCaptchaCount) {
        // 设置参数
        orgLoginVO.setCaptchaKey(captchaKey);
        orgLoginVO.setIpAddress(IpUtil.getIpAddress(request));
        orgLoginVO.setLoginCaptchaCount(loginCaptchaCount);
        // 手机号/邮箱+密码登录
        ServiceResult<UserLoginDTO> result = userAuthService.orgAndUsernameLogin(response, userLoginConvert.orgLoginVo2Dto(orgLoginVO));
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(userLoginConvert.userLoginDto2Vo(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 快速登录注册
     *
     * @param request        http请求对象
     * @param fastRegisterVO 用户注册vo
     * @return
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/6 14:30
     */
    @AuthIgnore
    @PostMapping("/fast/account/")
    public XmResultJson<UserLoginVO> fastRegister(HttpServletRequest request, @RequestBody FastRegisterVO fastRegisterVO) {
        // 设置参数
        OrgRegisterDTO orgRegisterDTO = userLoginConvert.fastRegisterVo2Dto(fastRegisterVO);
        orgRegisterDTO.setIpAddress(IpUtil.getIpAddress(request));
        // 快速登录注册
        ServiceResult<UserLoginDTO> result = userAuthService.fastRegister(orgRegisterDTO);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(userLoginConvert.userLoginDto2Vo(result.getData()), Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(userLoginConvert.userLoginDto2Vo(result.getData()));
    }

    /**
     * 螺丝帽验证
     *
     * @param luotestResponse
     * @return XmResultJson<String>
     * @author wangyunyun <yunyun.wang@idiaoyan.com>
     * @date 2022/3/11 13:24
     */
    @AuthIgnore
    @PostMapping("/captcha/luosimao/")
    public XmResultJson<String> luosimaoCheckCaptcha(@RequestParam(name = "luotest_response", required = false) String luotestResponse) {
        // 校验参数
        if (StringUtils.isBlank(luotestResponse)) {
            return XmResultJson.fail(ReqErrorCodeEnum.PARAM_LOST, luotestResponse);
        }
        ServiceResult<String> result = luosimaoService.checkCaptcha(luotestResponse);
        // 处理失败
        if (!result.isSuccess()) {
            return XmResultJson.fail(Integer.valueOf(result.getErrorCode()), result.getMsg());
        }
        // 处理成功
        return XmResultJson.success(result.getData());
    }

    /**
     * 获取用户的公司
     *
     * @param vo 用户名、密码
     * @return com.bestcem.xm.util.XmResultJson<com.bestcem.xm.user.service.dto.user.OrgInfoResultDTO>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/31 20:31
     */
    @AuthIgnore
    @PostMapping("/dingtalkapp/get_org")
    public XmResultJson<OrgInfoResultDTO> getOrg(@Valid @RequestBody GetOrgRequestVO vo) {
        ServiceResult<OrgInfoResultDTO> result = dingTalkService.getOrgInfo(vo.getUserName(), vo.getPassword());
        if (!result.isSuccess()) {
            return XmResultJson.fail(result.getErrorData(), result.getMsg());
        }
        return XmResultJson.success(result.getData());
    }

    /**
     * 钉钉免登录接口
     * 通过sessionId和org_code获取token信息
     *
     * @param vo sessionId、公司code
     * @return com.bestcem.xm.util.XmResultJson<java.lang.Object>
     * @author panyun <yun.pan@idiaoyan.com>
     * @date 2022/3/31 20:32
     */
    @AuthIgnore
    @PostMapping("/dingtalk/auth_token/")
    public XmResultJson<DingTalkTokenVO> authToken(@Valid @RequestBody AuthTokenRequestVO vo) {
        ServiceResult<UserGetTokenResultDTO> result = dingTalkService.authToken(vo.getSessionId(), vo.getOrgCode());
        if (!result.isSuccess()) {
            return XmResultJson.fail(result.getErrorData(), result.getMsg());
        }
        UserGetTokenResultDTO dto = result.getData();
        return XmResultJson.success(AuthorizationConverter.tokenDtoToVO(dto));
    }

}
